﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using System.Diagnostics;
using System.Reflection;
using Hallenberg.SmartClient.Interfaces;
using System.Collections.Specialized;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;

namespace Hallenberg.SmartClient.IO
{    
    internal class ModuleLoader : IModuleLoader
    {
        public void AutoLoadModules(ISmartClientApplication application, string[] startsWith)
        {
            Debug.Assert(application != null);
            if (application == null)
            {
                throw new ArgumentNullException("application");
            }

            Debug.Assert(startsWith != null);
            if (startsWith == null)
            {
                throw new ArgumentNullException("startsWith");
            }

            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                if (startsWith.Any(sw => assembly.FullName.StartsWith(sw, StringComparison.InvariantCultureIgnoreCase)))
                {
                    application.RegisterAssembly(assembly);
                }
            }
        }

        [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFile")]
        public void LoadModules(ISmartClientApplication application, string configFilePath)
        {
            Debug.Assert(application != null);
            if (application == null)
            {
                throw new ArgumentNullException("application");
            }

            Debug.Assert(!string.IsNullOrEmpty(configFilePath));
            if (string.IsNullOrEmpty(configFilePath))
            {
                throw new ArgumentNullException("configFilePath");
            }

            ///////////////////////////////////////////////////////////////////
            // Opening file stream.
            ///////////////////////////////////////////////////////////////////

            ModuleDefinitionCollection modules = null;

            using (FileStream fs = File.Open(application.ResolveRelativePath(configFilePath), FileMode.Open))
            {
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(ModuleDefinitionCollection));
                modules = xmlSerializer.Deserialize(fs) as ModuleDefinitionCollection;
            }

            ///////////////////////////////////////////////////////////////////
            // Register each module on the calling assembly.
            ///////////////////////////////////////////////////////////////////

            foreach (ModuleDefinition moduleDefinition in modules)
            {
                Debug.Assert(string.IsNullOrEmpty(moduleDefinition.FilePath) == false);
                if (string.IsNullOrEmpty(moduleDefinition.FilePath))
                {
                    throw new InvalidOperationException("Module [" + moduleDefinition.ModuleName + "] does not have a filepath specified");
                }

                Assembly assemblyModule = null;

                string resolvedPath = application.ResolveRelativePath(moduleDefinition.FilePath);

                assemblyModule = Assembly.LoadFile(resolvedPath);

                application.RegisterAssembly(assemblyModule);
            }
        }
    }
}
